package com.robot.topology.strategy.aco;

import java.util.ArrayList;
import java.util.List;

import com.robot.io.WriteInFile;
import com.robot.topology.graph.domain.Edge;
import com.robot.topology.graph.domain.Graph;
import com.robot.topology.graph.service.GraphManager;
import com.robot.topology.robot.domain.Robot;
import com.robot.topology.robot.service.RobotManagerImpl;
import com.robot.topology.robot.service.ant.RobotAntManagerImpl;
import com.robot.topology.tools.StrategyTools;

public class AntColonyOptimization {

	/**
	 * @param args
	 */
	public static final Integer []K = {5,10,15,50,100};
	public final Double alpha_decay = (double) 0.3;
	public Double delta_pheromone = (double) 0.5;
	private Integer nColony;
	
	public AntColonyOptimization(int colony){
		this.nColony = K[colony];
	}
	
	public void runAlgorithm(Graph graphToExplore) throws Exception{
		List<Edge> currentPath;
		String fileName=null;
		//Create ants
		List<Robot> theAnts = new ArrayList<Robot>();
		List<RobotManagerImpl> theManagers = new ArrayList<RobotManagerImpl>();
		//Strategy used ACO
		//fileName="100_ACO_"+this.nColony;
		fileName="AntColonyOptimization_"+this.nColony;

		// File writer
		//Get an empty file for each run
		WriteInFile writeInformation = new WriteInFile("resources", fileName,"CSV");
		writeInformation.initializeFile();

		//Create Manager for the graph
		GraphManager graphManager = new GraphManager(graphToExplore);

		// Create routine tables and assign to the corresponding Vertexes
		graphManager.createRoutineTables(graphToExplore);
		
		//Write in the file the RoutingTable		
		writeInformation.writeTextFile("Iteration;"+graphToExplore.getLabelEdges());
		writeInformation.writeTextFile("0;"+graphToExplore.getValueEdges());
				
		//Initializing ants of this colony 
		for(int i = 0; i<this.nColony ; i++ ){
			Robot ant = new Robot(graphToExplore.getInitialVertex(), graphToExplore.getGoalVertex(), graphToExplore.getEdges());
			RobotManagerImpl robotManager = new RobotAntManagerImpl(ant);
			theAnts.add(ant);
			theManagers.add(robotManager);
		}
		
		//Explore the graph until convergence
		//Colony goes to explore graph
		int i;
		for( i = 0; i < theAnts.size() && !graphManager.hasConverged() ; i++){
			Integer j = 0;
			//Se envian las hormigas de la colonia
			Robot ant = theAnts.get(i);
			do{
				j++;
				theManagers.get(i).moveRobotOneStep(j);
			}while( !ant.amIInGoalState() );
			
			//Update the pheromone
			currentPath= ant.getCurrentPath().getPath();
			for(Edge currentEdge : currentPath){
				if(currentEdge.getId() == "C1R3" || currentEdge.getId() == "C1C2"){
					this.updateEdgePheromone(currentEdge,currentPath.size());
				}
			}
			currentPath = ant.getUnusedEdges().getPath();
			for(Edge currentEdge : currentPath){
				if(currentEdge.getId() == "C1R3" || currentEdge.getId() == "C1C2"){
					this.updateEdgeDecay(currentEdge);
				}
			}
			
			//Actualizo las tablas por cada solucion encontrada
			graphManager.updateRoutineTables(graphToExplore);
			
			//Write in the file the RoutingTable values
			writeInformation.writeTextFile((i+1)+";"+graphToExplore.getValueEdges());
		}
//		writeInformation.writeTextFile( i+";"+graphToExplore.getValueEdges());
		System.out.println("Colony:"+this.nColony+"  Ant:"+i);
		

	}
	
	
	public void updateEdgePheromone(Edge edgeTUpdate, Integer nArcs) {
		Double pheromone = edgeTUpdate.getWeight();
		edgeTUpdate.setWeight(StrategyTools.ACO_Reinforce(pheromone, nArcs, this.delta_pheromone));
	}

	public void updateEdgeDecay(Edge edgeTUpdate) {
		Double pheromone = edgeTUpdate.getWeight();
		edgeTUpdate.setWeight(StrategyTools.ACO_Decay(pheromone, alpha_decay));
	}

}
